package javaer.starter.idea;

import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiJavaFile;
import javaer.starter.constants.JarTypeEnum;
import javaer.starter.constants.ModuleDependTypeEnum;
import javaer.starter.constants.SymbolEnum;
import javaer.starter.idea.util.IdeaUtils;
import javaer.starter.idea.window.JavaerStarterUI;
import javaer.starter.idea.window.component.ModuleTable;
import javaer.starter.idea.window.component.PomXmlTemplateTextArea;
import javaer.starter.idea.window.component.TemplateTable;
import javaer.starter.model.*;
import javaer.starter.model.context.MavenContext;
import javaer.starter.model.context.StarterContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Exclusion;
import org.jetbrains.idea.maven.project.MavenProject;

import java.nio.file.Paths;
import java.util.*;

import static javaer.starter.idea.Constants.*;

/**
 * @author yangzhen
 * @date 2023/7/11 14:12
 * @since 1.0.0
 */
public class ContextResolver {

    public static StarterContext getStarterContext(JavaerStarterUI javaerStarterUI) {
        StarterContext starterContext = new StarterContext();
        initStarterContext(javaerStarterUI, starterContext);
        init_starter_type(javaerStarterUI, starterContext);
        init_starter_module(javaerStarterUI, starterContext);
        init_starter_dependency(javaerStarterUI, starterContext);
        init_starter_template(javaerStarterUI, starterContext);
        return starterContext;
    }

    /**
     * 初始化基本信息
     * 基础包名
     * artifactId、pomPath
     *
     * @param javaerStarterUI
     * @param starterContext
     */
    public static void initStarterContext(JavaerStarterUI javaerStarterUI, StarterContext starterContext) {
        String packageValue = StringUtils.trim(javaerStarterUI.packageValue.getText());
        displayError(packageValue, PACKAGE_MUST);
        starterContext.setBasePackage(packageValue);
        starterContext.setRootArtifactId(javaerStarterUI.mavenContext.rootArtifactId);
        Map<String, String> artifactId_pomPath = javaerStarterUI.mavenContext.artifactId_pomPath;
        artifactId_pomPath.forEach((k, v) ->
                starterContext.addArtifactIdModulePath(k, Paths.get(v).getParent())
        );
        starterContext.addQualifiedNames(javaerStarterUI.mavenContext.qualifiedNames);
    }

    /**
     * 初始化表starter_type数据
     *
     * @param javaerStarterUI
     * @param starterContext
     */
    public static void init_starter_type(JavaerStarterUI javaerStarterUI, StarterContext starterContext) {
        String typeId = StringUtils.trim(javaerStarterUI.typeValue.getText());
        displayError(typeId, TYPE_ID_MUST);
        String typeName = StringUtils.trim(javaerStarterUI.typeName.getText());
        displayError(typeName, TYPE_NAME_MUST);
        String typeDesc = StringUtils.trim(javaerStarterUI.typeDesc.getText());
        displayError(typeDesc, TYPE_DESC_MUST);
        StarterTypeModel starterTypeModel = new StarterTypeModel();
        starterTypeModel.setTypeName(typeName);
        starterTypeModel.setDescription(typeDesc);
        setGmt(starterTypeModel);
        starterTypeModel.setTypeId(typeId);
        starterContext.setStarterTypeModel(starterTypeModel);
    }

    /**
     * 初始化表starter_module数据
     *
     * @param javaerStarterUI
     * @param starterContext
     */
    public static void init_starter_module(JavaerStarterUI javaerStarterUI, StarterContext starterContext) {
        MavenContext mavenContext = javaerStarterUI.mavenContext;
        // 根项目
        String rootArtifactId = mavenContext.rootArtifactId;
        Set<String> artifactIds = mavenContext.artifactIds;
        Map<String, Set<String>> artifactId_moduleDependency = mavenContext.artifactId_moduleDependency;
        Map<String, List<Dependency>> artifactId_dependency = mavenContext.artifactId_dependency;
        ModuleTable customModuleTable = javaerStarterUI.customModuleTable;
        for (String artifactId : artifactIds) {
            // 过滤根项目
            if (artifactId.equals(rootArtifactId)) {
                continue;
            }
            ModuleModel moduleModel = new ModuleModel();
            moduleModel.setTypeId(starterContext.getTypeId());
            // 截取模块标识
            moduleModel.setModuleId(artifactId.substring(rootArtifactId.length() + 1).toUpperCase());
            String moduleName = customModuleTable.getModuleName(artifactId);
            if (StringUtils.isBlank(moduleName)) {
                moduleName = moduleModel.getModuleId();
            }
            moduleModel.setModuleName(moduleName);
            moduleModel.setRequired(customModuleTable.isRequired(artifactId));
            // 获取是否启动模块
            moduleModel.setStarter(customModuleTable.isStarter(artifactId));
            Set<String> moduleDependencies = artifactId_moduleDependency.get(artifactId);
            Set<ModuleDependencyModel> mds = new HashSet<>();
            if (Objects.nonNull(moduleDependencies)) {
                // 模块依赖
                for (String moduleDependencyId : moduleDependencies) {
                    String moduleDependencyIdUpperCase = moduleDependencyId.substring(rootArtifactId.length() + 1).toUpperCase();
                    mds.add(getModuleDependency(
                            starterContext.getTypeId(),
                            moduleModel.getModuleId(),
                            ModuleDependTypeEnum.MODULE.getValue(),
                            moduleDependencyIdUpperCase
                    ));
                }
            }
            List<Dependency> dependencies = artifactId_dependency.get(artifactId);
            if (Objects.nonNull(dependencies)) {
                // 依赖
                for (Dependency dependency : dependencies) {
                    mds.add(getModuleDependency(
                            starterContext.getTypeId(),
                            moduleModel.getModuleId(),
                            ModuleDependTypeEnum.JAR.getValue(),
                            dependency.getArtifactId()
                    ));
                }
            }
            starterContext.addModuleDependencies(mds);
            setGmt(moduleModel);
            // 存储临时变量
            starterContext.addModuleIdArtifactId(moduleModel.getModuleId(), artifactId);
            starterContext.addModuleModel(moduleModel);
        }
    }

    private static ModuleDependencyModel getModuleDependency(String typeId, String moduleId, int depType, String artifactId) {
        ModuleDependencyModel md = new ModuleDependencyModel();
        md.setTypeId(typeId);
        md.setModuleId(moduleId.toUpperCase());
        md.setDepType(depType);
        md.setDepId(artifactId);
        setGmt(md);
        return md;
    }

    public static void init_starter_dependency(JavaerStarterUI javaerStarterUI, StarterContext starterContext) {
        MavenContext mavenContext = javaerStarterUI.mavenContext;
        Map<String, List<Dependency>> artifactId_dependency = mavenContext.artifactId_dependency;
        Set<DependencyModel> dependencies = new HashSet<>();
        Set<DependencyExcludedModel> excludedDependencies = new HashSet<>();
        artifactId_dependency.forEach((k, v) -> {
            for (Dependency dependency : v) {
                DependencyModel dependencyModel = getDependencyModel(starterContext, dependency);
                dependencies.add(dependencyModel);
                List<Exclusion> exclusions = dependency.getExclusions();
                if (Objects.nonNull(exclusions)) {
                    for (Exclusion exclusion : exclusions) {
                        DependencyExcludedModel dependencyExcludedModel = new DependencyExcludedModel();
                        dependencyExcludedModel.setTypeId(starterContext.getTypeId());
                        dependencyExcludedModel.setDepId(dependency.getArtifactId());
                        dependencyExcludedModel.setGroupId(exclusion.getGroupId());
                        dependencyExcludedModel.setArtifactId(exclusion.getArtifactId());
                        setGmt(dependencyExcludedModel);
                        excludedDependencies.add(dependencyExcludedModel);
                    }
                }
            }
        });
        String springBoot = javaerStarterUI.pomXmlTemplateTextArea.getSpringBoot();
        if (StringUtils.isNotBlank(springBoot)) {
            String[] springBootDep = springBoot.split(":");
            if (springBootDep.length >= 3) {
                Dependency dependency = new Dependency();
                dependency.setGroupId(springBootDep[0]);
                dependency.setArtifactId(springBootDep[1]);
                dependency.setVersion(springBootDep[2]);
                DependencyModel dependencyModel = getDependencyModel(starterContext, dependency);
                dependencyModel.setDepId(SymbolEnum.POM_PARENT.getSymbol());
                dependencies.add(dependencyModel);
            }
        }

        starterContext.addDependencies(dependencies);
        starterContext.addExcludedDependencies(excludedDependencies);
    }

    private static DependencyModel getDependencyModel(StarterContext starterContext, Dependency dependency) {
        DependencyModel dependencyModel = new DependencyModel();
        dependencyModel.setTypeId(starterContext.getTypeId());
        dependencyModel.setCategory(dependency.getGroupId());
        dependencyModel.setDepId(dependency.getArtifactId());
        dependencyModel.setGroupId(dependency.getGroupId());
        dependencyModel.setArtifactId(dependency.getArtifactId());
        dependencyModel.setVersion(dependency.getVersion());
        dependencyModel.setScope(dependency.getScope());
        dependencyModel.setOptional(dependency.getOptional());
        dependencyModel.setClassifier(dependency.getClassifier());
        dependencyModel.setDepType(JarTypeEnum.JAR.getType());
        setGmt(dependencyModel);
        return dependencyModel;
    }

    public static void init_starter_template(JavaerStarterUI javaerStarterUI, StarterContext starterContext) {
        MavenContext mavenContext = javaerStarterUI.mavenContext;
        Project project = javaerStarterUI.project;
        String typeId = starterContext.getTypeId();
        String basePackage = starterContext.getBasePackage();
        String basePackagePath = basePackage.replace(SymbolEnum.POINT.getSymbol(), SymbolEnum.SLASH.getSymbol());

        PomXmlTemplateTextArea pomXmlTemplateTextArea = javaerStarterUI.pomXmlTemplateTextArea;

        String rootArtifactId = javaerStarterUI.mavenContext.rootArtifactId;
        Set<TemplateModel> result = new HashSet<>();
        mavenContext.artifactId_psiFile.forEach((k, list) -> {
            String moduleSuffix = k;
            if (k.equals(rootArtifactId)) {
                moduleSuffix = SymbolEnum.ROOT.getSymbol();
            } else {
                moduleSuffix = moduleSuffix.replace(rootArtifactId + SymbolEnum.HORIZONTAL_LINE.getSymbol(), "");
            }

            Module module = mavenContext.artifactId_module.get(k);
            MavenProject mavenProject = IdeaUtils.getMavenProject(project, module);
            String modulePath = mavenProject.getFile().getParent().getPath();
            String srcMainJavaPath = modulePath + SymbolEnum.SLASH.getSymbol() + SymbolEnum.SRC_MAIN_JAVA.getSymbol();
            String srcMainResourcesPath = modulePath + SymbolEnum.SLASH.getSymbol() + SymbolEnum.SRC_MAIN_RESOURCES.getSymbol();
            String modulePath_basePackagePath_srcMainJavaPath = srcMainJavaPath + SymbolEnum.SLASH.getSymbol() + basePackagePath;
            for (PsiFile psiFile : list) {
                TemplateModel templateModel = new TemplateModel();
                String filepath = psiFile.getVirtualFile().getPath();
                String relativePath = "";
                if (filepath.startsWith(srcMainJavaPath) && psiFile instanceof PsiJavaFile) {
                    templateModel.setSourceDirectory(SymbolEnum.SRC_MAIN_JAVA.getSymbol());
                    relativePath = getRelativePath(psiFile, modulePath_basePackagePath_srcMainJavaPath.length());
                } else if (filepath.startsWith(srcMainResourcesPath)) {
                    templateModel.setSourceDirectory(SymbolEnum.SRC_MAIN_RESOURCES.getSymbol());
                    relativePath = getRelativePath(psiFile, srcMainResourcesPath.length());
                } else {
                    templateModel.setSourceDirectory("");
                    relativePath = getRelativePath(psiFile, modulePath.length());
                }
                if (relativePath.startsWith(SymbolEnum.SLASH.getSymbol())) {
                    relativePath = relativePath.substring(1);
                }
                templateModel.setRelativePath(relativePath);
                templateModel.setModuleId(moduleSuffix.toUpperCase());
                templateModel.setTypeId(typeId);
                templateModel.setDepId(TemplateTable.getDepId(k, psiFile.getName()));
                templateModel.setTemplateName(psiFile.getName());
                templateModel.setContent(psiFile.getText());
                setGmt(templateModel);
                result.add(templateModel);
            }
            result.add(getPomXml(typeId, moduleSuffix, pomXmlTemplateTextArea));
        });
        starterContext.addTemplates(result);
    }

    private static TemplateModel getPomXml(String typeId, String moduleId, PomXmlTemplateTextArea pomXmlTemplateTextArea) {
        TemplateModel templateModel = new TemplateModel();
        templateModel.setRelativePath("");
        templateModel.setModuleId(moduleId);
        templateModel.setTypeId(typeId);
        templateModel.setDepId("");
        templateModel.setTemplateName(SymbolEnum.POM_XML.getSymbol());
        templateModel.setContent(pomXmlTemplateTextArea.getPomXml());
        templateModel.setSourceDirectory("");
        setGmt(templateModel);
        return templateModel;
    }

    private static String getRelativePath(PsiFile psiFile, int prefixPathLength) {
        String path = psiFile.getVirtualFile().getParent().getPath();
        return path.substring(prefixPathLength);
    }

    /**
     * 这是创建时间和修改时间
     *
     * @param baseModel
     */
    public static void setGmt(BaseModel baseModel) {
        baseModel.setGmtCreate(System.currentTimeMillis());
        baseModel.setGmtModified(System.currentTimeMillis());
    }

    /**
     * 校验参数和弹框提示
     *
     * @param value
     * @param msg
     */
    public static void displayError(String value, String msg) {
        if (StringUtils.isBlank(value)) {
            throw new RuntimeException(msg);
        }
    }
}
